package Controller;

import Settings.ServerData;
import database.LoadFromDatabase;
import java.util.ArrayList;
import org.apache.log4j.Logger;
import worker.TCPConnectionHandler;
import worker.UDPMessageHandler;

public class ReInitializer extends Thread {

    private static ReInitializer reInitializerObj = null;
    private static Logger logger = Logger.getLogger(ReInitializer.class);
    private boolean running;

    public static ReInitializer getInstance() {
        if (reInitializerObj == null) {
            createReInitializerObj();
        }
        return reInitializerObj;
    }

    private static synchronized void createReInitializerObj() {
        if (reInitializerObj == null) {
            try {
                reInitializerObj = new ReInitializer();
            } catch (Exception ex) {
                logger.fatal("exception while creating ReInitializer Thread", ex);
            }
        }
    }

    @Override
    public void run() {
        running = true;
        logger.debug("ReInitializer Thread started successfully");
        while (running) {

            //loading test settings from DB

            if (LoadFromDatabase.getInstance().loadTestSettings()) {

                ServerData.tcpPortList.clear();
                ServerData.udpPortList.clear();

                // adding new tests to the server (newly added or edited port)
                for (int i = 0; i < ServerData.testSettingsObjects.size(); i++) {
                    ServerData.tcpPortList.add(ServerData.testSettingsObjects.get(i).port);
                    if (ServerData.testSettingsObjects.get(i).transmission_protocol.equals("UDP")) {
                        ServerData.udpPortList.add(ServerData.testSettingsObjects.get(i).port);
                    }
                    if (!ServerData.portToTCPthreadMap.containsKey(ServerData.testSettingsObjects.get(i).port)) {

                        logger.debug("New TCP thread added with port: " + ServerData.testSettingsObjects.get(i).port);
                        TCPConnectionHandler tcpConObj = new TCPConnectionHandler(ServerData.testSettingsObjects.get(i).port);
                        tcpConObj.start();

                        ServerData.portToTCPthreadMap.put(ServerData.testSettingsObjects.get(i).port, tcpConObj);

                    }

                    if (!ServerData.portToUDPthreadMap.containsKey(ServerData.testSettingsObjects.get(i).port) && ServerData.testSettingsObjects.get(i).transmission_protocol.equals("UDP")) {
                        logger.debug("New UDP thread added with port: " + ServerData.testSettingsObjects.get(i).port);
                        UDPMessageHandler udpMsgObj = new UDPMessageHandler(ServerData.testSettingsObjects.get(i).port);
                        udpMsgObj.start();

                        ServerData.portToUDPthreadMap.put(ServerData.testSettingsObjects.get(i).port, udpMsgObj);
                    }


                }

                //deleting any deleted/edited listening ports
                ArrayList<Integer> tcpKeys = new ArrayList<Integer>(ServerData.portToTCPthreadMap.keySet());
                ArrayList<Integer> udpKeys = new ArrayList<Integer>(ServerData.portToUDPthreadMap.keySet());

                for (int i = 0; i < tcpKeys.size(); i++) {
                    if (!ServerData.tcpPortList.contains(tcpKeys.get(i))) {
                        ServerData.portToTCPthreadMap.get(tcpKeys.get(i)).shutDown();
                        ServerData.portToTCPthreadMap.remove(tcpKeys.get(i));
                    }
                }

                for (int i = 0; i < udpKeys.size(); i++) {
                    if (!ServerData.udpPortList.contains(udpKeys.get(i))) {
                        ServerData.portToUDPthreadMap.get(udpKeys.get(i)).shutDown();
                        ServerData.portToUDPthreadMap.remove(udpKeys.get(i));
                    }
                }


            } else {
                logger.fatal("Failed to load Basic Test Settings in ReInitializer Thread");
            }

            try {
                Thread.sleep(300000); //5 mimutes
            } catch (InterruptedException ex) {
                logger.fatal("ReInitializer Thread has been interrupted to work/stop");
            }

        }

    }

    public void shutDown() {
        running = false;
        this.interrupt();
    }
}
